﻿using SharpConfig;
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace LL2025.Ini.Lib
{
    public static class IniConfig
    {
        public enum IniType
        {
            Read,
            Write
        }
        public static Encoding _encoding = null;
        public static string _path = "";
        public static Configuration Path(string path, IniType iniType = IniType.Read, Encoding encoding = null)
        {
            _encoding = encoding;
            _path = path;
            if (iniType == IniType.Write)
                return new Configuration();
            if (!Directory.Exists(System.IO.Path.GetDirectoryName(path))) Directory.CreateDirectory((System.IO.Path.GetDirectoryName(path)));
            return Configuration.LoadFromFile(path, encoding);
        }
        public static Configuration CreateSectionsFromOneObject(this Configuration cfg, object p, string cfgname = "")
        {
            if (cfgname == "")
                cfg.Add(Section.FromObject(p.GetType().Name, p));
            else
                cfg.Add(Section.FromObject(cfgname, p));
            return cfg;
        }
        public static bool SaveCacheToFile(this Configuration cfg)
        {
            try
            {
                cfg.SaveToFile(_path, _encoding);
            }
            catch { return false; }
            return true;
        }
        public static async Task<bool> SaveCacheToFileAsync(this Configuration cfg)
        {
            return await Task.Run(() =>
            {
                return cfg.SaveCacheToFile();
            });
        }
        public static T LoadFromIFile<T>(this Configuration cfg) where T : new()
        {
            T val = new T();
            cfg[val.GetType().Name].SetValuesTo(val);
            return val;
        }
        public static T LoadFromIFile<T>(this Configuration cfg, string name) where T : new()
        {
            T val = new T();
            cfg[name].SetValuesTo(val);
            return val;
        }

        public static void SetNullPropertiesToDefault<T>(T obj) where T : class
        {
            if (obj == null) throw new ArgumentNullException(nameof(obj));

            PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var property in properties)
            {
                object value = property.GetValue(obj);

                if (value == null)
                {
                    if (property.PropertyType.IsValueType)
                    {
                        // 对于值类型，设置为默认值（通常是0、false、\0等）  
                        // 注意：对于Nullable<T>，默认值将是null，但我们可以通过其他方式处理  
                        if (Nullable.GetUnderlyingType(property.PropertyType) != null)
                        {
                            // 如果属性是可空类型，则设置为该可空类型的默认值（即null的包装器）  
                            property.SetValue(obj, Activator.CreateInstance(Nullable.GetUnderlyingType(property.PropertyType)));
                        }
                        else
                        {
                            // 对于非可空的值类型，设置为该类型的默认值  
                            property.SetValue(obj, Activator.CreateInstance(property.PropertyType));
                        }
                    }
                    else
                    {
                        // 对于引用类型，我们可以选择设置为string.Empty或其他合适的默认值  
                        // 这里以string.Empty为例  
                        if (property.PropertyType == typeof(string))
                        {
                            property.SetValue(obj, string.Empty);
                        }
                        // 你可以根据需要为其他引用类型添加逻辑  
                    }
                }
                // 注意：对于更复杂的类型（如集合、自定义类等），你可能需要更复杂的逻辑来设置默认值  
            }
        }

        private static void PrintConfig(Configuration cfg)
        {
            foreach (Section section in cfg)
            {
                Console.WriteLine("[{0}]", section.Name);

                foreach (Setting setting in section)
                {
                    Console.Write("  ");

                    if (setting.IsArray)
                        Console.Write("[Array, {0} elements] ", setting.ArraySize);

                    Console.WriteLine(setting.ToString());
                }
                Console.WriteLine();
            }
        }
    }
}
